#pragma once

#include <iostream>
#include <string>
#include <functional>
#include <memory>
#include <thread>
#include <mutex>

using namespace std;

typedef std::function<void(int)> callback_f;
typedef std::function<int(const string)> callback_ff;

/**
 *     调用者(接收回调)
*/
class Caller
{
public:
    Caller()
    {
        m_threadPtr.reset(new thread(std::bind(&Caller::threadFunc, this)));
    }

    ~Caller()
    {
        std::cout << "~Caller()" << endl;
        m_threadPtr->join();
    }

    void threadFunc()
    {
        std::cout << "Caller thread start" << endl;
        int count = 0;
        static int type = 0;
        while (!m_isExit)
        {
            count++;
            if ( count == 2 )
            {
                type++;
                std::cout << "Caller Use Callback - type = " << type << endl;
                m_callback(type);
                count = 0; 
            }
            std::this_thread::sleep_for(std::chrono::seconds(1));           // 延时处理
        }
    }

    static void setCallBack(callback_f cf)
    {
        lock_guard<std::mutex> guardLck(m_mutex);
        m_callback = cf;
    }

    void setExit(bool isExit)
    {
        m_isExit = isExit;
    }

private:
    bool m_isExit = false;
    unique_ptr<std::thread> m_threadPtr;
    static std::mutex m_mutex;
    static callback_f m_callback;              // 回调接收
};

std::mutex Caller::m_mutex;
callback_f Caller::m_callback;

class Caller1
{
public:
    Caller1()
    {
        m_threadPtr.reset(new thread(std::bind(&Caller1::threadFunc, this)));
    }

    ~Caller1()
    {
        std::cout << "~Caller1()" << endl;
        m_threadPtr->join();
    }

    void threadFunc()
    {
        std::cout <<  "Caller1 thread start" << endl;
        int count = 0;
        static int type1 = 0;
        while (!m_isExit)
        {
            count++;
            if ( count == 2 )
            {
                type1++;
                std::cout << "Caller1 Use Callback - type1 = " << type1 << endl;
                m_callback(std::to_string(type1));
                count = 0; 
            }
            std::this_thread::sleep_for(std::chrono::seconds(1));           // 延时处理
        }
    }

    static void setCallBack(callback_ff cf)
    {
        lock_guard<std::mutex> guardLck(m_mutex);
        m_callback = cf;
    }

    void setExit(bool isExit)
    {
        m_isExit = isExit;
    }

private:
    bool m_isExit = false;
    unique_ptr<std::thread> m_threadPtr;
    static std::mutex m_mutex;
    static callback_ff m_callback;              // 回调接收
};

std::mutex Caller1::m_mutex;
callback_ff Caller1::m_callback;


/**
 *      被调用者(响应回调) - 上层
*/
class Callee
{
public:
    Callee()
    {

    }

    ~Callee()
    {
        std::cout << "~Callee()" << endl;
    }

    void func(int type)
    {
        std::cout << " Callee func() - type: " << type  << endl;
    }

    int func1(const string &str)
    {
        std::cout << " Callee1 func() - str: " << str  << endl;
        return 0;
    }

};

/**普通函数作为回调函数**/
void functionA()
{
    std::cout << "functionA" << endl;
}

void functionB()
{
    std::cout << "functionB" << endl;
}

void callback(void(*cb)())
{
    std::cout << "callback" << endl;
    cb();
}

typedef std::function<void(const string)> callabck_p;

class ProgramA
{
public:
    ProgramA(){}

    static void func_pa(const string &str)
    {
        std::cout << "func_pa: " << str << endl;
    }

};

class ProgramB
{
public:
    ProgramB(){}

    void setCallback(const callabck_p &cp, const string &str)
    {
        std::cout << "ProgramB::setCallback" << endl;
        cp(str);
    }
};


/**结合std::bind和std::function使用**/








